# -*- coding:utf-8 -*-
from ui_cali import Ui_MultiBaseCalibration
# import pyqtgraph as pg
import datetime, copy, os
from PyQt5 import QtWidgets,QtSql
from PyQt5.QtCore import Qt
import logging
from FlowLayout import FlowLayout
import myglobal
import mydb
# import matplotlib.pyplot as plt
# from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FC
import pyqtgraph as pg
from CheckBoxDelegateQt import CheckBoxDelegateQt
import numpy as np
from scipy.optimize import leastsq
methodid=1
dataBase_maxChannel=10
def Fun(p,x):                        # 定义拟合函数形式
    a1,a2,a3 = p
    return a1*x**2+a2*x+a3
def error (p,x,y):                    # 拟合残差
    return Fun(p,x)-y 
def Fun2(p,x):                        # 定义拟合函数形式
    a2,a3 = p
    return a2*x+a3
def error2(p,x,y):                    # 拟合残差
    return Fun2(p,x)-y 
class Cali(QtWidgets.QDialog, ):
    ui = Ui_MultiBaseCalibration()
    def __init__(self):
        super().__init__()
        self.ui.setupUi(self)
        self.setWindowTitle('基础校正')
        # self.db=mydb.MyDb()
        self.model = QtSql.QSqlTableModel()
        self.model.setTable("curvedata")  # setQuery(cmd)
        self.ui.twData.setModel(self.model)
        self.ui.twData.setSortingEnabled(True)
        self.checkDele=CheckBoxDelegateQt()
        self.ui.twData.setItemDelegateForColumn(5,self.checkDele)
        myglobal.fields=self.to_fields(myglobal.db.table_info("STD_result"))
        # self.baseItems = [[] for i in range(0, dataBase_maxChannel)]
        # self.inittwData()
        # self.initGraph()
        # self.currentChannel = 0
        # # self.rbtn0.setChecked(1)
        # self.btnNew.clicked.connect(self.btnNew_clicked)
        # # self.btnNew.setVisible(False)
        self.ui.btnCalculation.clicked.connect(self.draw)
        # self.btnDelete.clicked.connect(self.btnDelete_clicked)
        # self.btnLinearity.clicked.connect(self.btnLinearity_clicked)
        self.ui.pushButton_std_result.clicked.connect(self.import_std_result)
        self.ui.pushButton_std.clicked.connect(self.import_std)  
        self.ui.pushButton_select.clicked.connect(self.edit_standard)                
        self.h = FlowLayout(self.ui.groupBox)
        self.chks = []
        # self.setAcceptDrops(True)
        self.resetItems()
        # self.showMaximized()
        self.firstChannel()
        self.add_Figure()
        self.resize(1000,1000)
    def pgWidget(self):
        pg.setConfigOptions(imageAxisOrder='row-major')
        win = pg.GraphicsLayoutWidget()
        win.setWindowTitle('pyqtgraph example: Image Analysis')
        # A plot area (ViewBox + axes) for displaying the image
        self.fig= win.addPlot(title="")#plot item
        # print(p1)
        # ptx=[1,2,3]
        # pty=[4,5,6]
        # self.graph.plot(x=ptx, y=pty, pen=None, symbol='o')
        # for i in self.curve:
        #     i.clear()
        #     self.graph.removeItem(i)
        # self.curve.clear()
        # ptx = []
        # pty = []
        # for item in self.baseItems[self.currentChannel]:
        #     if item.include:
        #         ptx.append(item.area)
        #         pty.append(item.standard)
        #     # item.calculated = Factor.calculateResultFromArea(item.area, item.weight, item.flux, factor)
        # if len(ptx) > 0:
        #     self.curve.append(self.graph.plot(x=ptx, y=pty, pen=None, symbol='o'))
        #     xe = max(ptx)
        #     ye = factor.baseK * xe + factor.baseB
        #     ys = factor.baseK * 0 + factor.baseB
        #     self.curve.append(self.graph.plot(x=[0, xe], y=[ys, ye], pen=pg.mkPen(color="r", width=2), style=Qt.DashLine))
        return win
    def add_Figure(self):
        main_layout = QtWidgets.QVBoxLayout(self.ui.widget)
        # self.fig = plt.Figure()
        # self.canvas = FC(self.fig)
        main_layout.addWidget(self.pgWidget())
        self.ui.widget.setLayout(main_layout)
    def draw(self):
        # nsample=20
        # x = np.linspace(0, 10, nsample)
        # def square(num):
        #     return 3*num ** 2+2*num+1
        # y= square(x)
        x=[]
        y=[]
        for row in range(self.model.rowCount()):
            record = self.model.record(row)
            x1= myglobal.myfloat(record.value(4))
            y1= myglobal.myfloat(record.value(3))
            use= record.value(5)
            if use==1:
                x.append(x1)
                y.append(y1)
        x=np.array(x)
        y=np.array(y)
        if self.ui.radioButton_1.isChecked():
            self.fit2(x,y) 
        else:
            self.fit3(x,y) 
    def fit2(self,x,y):
        # p_value = [-2,5,10] # 原始数据的参数
        p0 = [1.0,0.0] # 拟合的初始参数设置
        para =leastsq(error2, p0, args=(x,y),full_output=True) # 进行拟合
        y_fitted = Fun2(para[0],x) # 画出拟合后的曲线
        # print(dir(self.fig))
        self.fig.clear()
        # ax = self.fig.add_subplot(111)
        # ax.cla()  # TODO:删除原图，让画布上只有新的一次的图
        # self.fig.plot(x, y, 'o', label='data')
        self.fig.plot(x=x, y=y, pen=None, symbol='o')
        self.fig.plot(x=x, y=y_fitted, pen=pg.mkPen(color="r", width=2), style=Qt.DashLine)
        # self.fig.plot(x, y_fitted, 'r--.',label='OLS')
        # ax.legend(loc='best')
        # self.canvas.draw()  # TODO:这里开始绘制
        # plt.figure
        # plt.plot(x,y,'r', label = 'Original curve')
        # plt.plot(x,y_fitted,'-b', label ='Fitted curve')
        # plt.legend()
        # plt.show()
        ssErr = (para[2]['fvec']**2).sum()
        ssTot = ((y-y.mean())**2).sum()
        rsquared = 1-(ssErr/ssTot )  
        params=""
        params+="x1="+str(para[0][0])+"\n"
        params+="x0="+str(para[0][1])+"\n"
        params+="r="+str(rsquared)+"\n"
        self.ui.lblParams.setText(params)
        print(para) 
        print(para[0])
        print(rsquared)
        # cmd="insert into curvexishu(methodid,ele,x2,x1,x0) values()"
        x2=0
        x1=para[0][0]
        x0=para[0][1]
        myglobal.db.save_xishu(methodid,myglobal.ele,x2,x1,x0,rsquared)        
    def fit3(self,x,y):
        # p_value = [-2,5,10] # 原始数据的参数
        p0 = [0.0,1.0,0.0] # 拟合的初始参数设置
        para =leastsq(error, p0, args=(x,y),full_output=True) # 进行拟合
        y_fitted = Fun (para[0],x) # 画出拟合后的曲线
        ax = self.fig.add_subplot(111)
        self.fig.clear()#ax.cla()  # TODO:删除原图，让画布上只有新的一次的图
        self.fig.plot(x=x, y=y, pen=None, symbol='o')
        self.fig.plot(x=ptx, y=y_fitted, pen=None, symbol='o')#x, y_fitted, 'r--.',label='OLS')
        # ax.legend(loc='best')
        # self.canvas.draw()  # TODO:这里开始绘制
        # plt.figure
        # plt.plot(x,y,'r', label = 'Original curve')
        # plt.plot(x,y_fitted,'-b', label ='Fitted curve')
        # plt.legend()
        # plt.show()
        ssErr = (para[2]['fvec']**2).sum()
        ssTot = ((y-y.mean())**2).sum()
        rsquared = 1-(ssErr/ssTot )  
        params=""
        params+="x2="+str(para[0][0])+"\n"
        params+="x1="+str(para[0][1])+"\n"
        params+="x0="+str(para[0][2])+"\n"
        params+="r="+str(rsquared)+"\n"
        self.ui.lblParams.setText(params)
        x2=para[0][0]
        x1=para[0][1]
        x0=para[0][2]
        myglobal.db.save_xishu(methodid,myglobal.ele,x2,x1,x0,rsquared)        
        print(para) 
        print(para[0])
        print(rsquared)
    # def fit0(self,x,y):
    #     X = np.column_stack((x, x**2)) #按照需求去添加一列x平方，这样就有x和x平方这2列数据了
    #     X = sm.add_constant(X) #再添加一个全为1的列
    #     # beta = np.array([5, 2, 3]) #定义回归系数咯
    #     # e = np.random.normal(size=nsample) #来生成size为nsample个的高斯噪声
    #     # y = np.dot(X, beta) + e #通过计算矩阵的点乘内积，再加上高斯噪声的方式，生成需要用的模拟数据
    #     # print(X,y)
    #     model = sm.OLS(y,X) #利用模拟数据的因变量y与自变量们(1,x,x^2)进行最小二乘回归，返回model
    #     results = model.fit() #拟合数据，返回拟合结果啦
    #     print(results.params) #查看拟合出的回归系
    #     print(results.summary())
    #     y_fitted = results.fittedvalues #给出y的拟合值
    #     ax = self.fig.add_subplot(111)
    #     ax.cla()  # TODO:删除原图，让画布上只有新的一次的图
    #     ax.plot(x, y, 'o', label='data')
    #     ax.plot(x, y_fitted, 'r--.',label='OLS')
    #     ax.legend(loc='best')
    #     # # cbbar=ax.scatter(x,y,'-o')
    #     # # self.fig.colorbar(cbbar)
    #     self.canvas.draw()  # TODO:这里开始绘制
    def to_fields(self,data):
        fields = [{"ele": None, "name": "id", "title": "id", "visible": False
                        }, {"ele": None, "name": "sampleid", "title": "样品编号", "visible": True
                            }, {"ele": None, "name": "beizhu", "title": "备注", "visible": True
                                }, {"ele": None, "name": "mass", "title": "质量", "visible": True
                                    }, {"ele": None, "name": "volume", "title": "体积", "visible": True
                                        }, {"ele": None, "name": "xishi", "title": "稀释倍数", "visible": True
                                            }]       
        if len(data)>7:
            for one in data[7:]:
                fields.append({"ele": one[:-1], "name": one, "title": one[:-1], "visible": True})
        return fields        
    def genchks(self):
        if len(self.chks) < len(myglobal.fields):
            # logging.info(list(range(len(self.chks), len(self.fields))))
            for i in range(len(self.chks), len(myglobal.fields)):
                c = QtWidgets.QRadioButton("")
                self.h.addWidget(c)
                c.pressed.connect(
                    lambda val=i: self.field_click(val)
                )
                self.chks.append(c)
    def field_click(self, i):
        logging.info(self.sender())
        logging.info(i)
        logging.info(myglobal.fields[i]["visible"])
        myglobal.fields[i]["visible"] = True
        logging.info(myglobal.fields[i]["ele"])
        myglobal.ele=myglobal.fields[i]["ele"]
        self.model.setFilter("ele =  '" + myglobal.fields[i]["ele"]+"'")
    def resetItems(self):
        self.genchks()
        logging.info(len(self.chks))
        firstEle=True
        for i in range(len(myglobal.fields)):
            if myglobal.fields[i].get("ele") is None:
                self.chks[i].setVisible(False)
            else:
                if firstEle:
                    myglobal.fields[i]["visible"]=True
                    self.chks[i].setChecked(myglobal.fields[i]["visible"])
                    self.chks[i].setText(myglobal.fields[i]["title"])
                    self.chks[i].setVisible(True)
                    firstEle=False
                else:
                    myglobal.fields[i]["visible"]=False
                    self.chks[i].setChecked(myglobal.fields[i]["visible"])
                    self.chks[i].setText(myglobal.fields[i]["title"])
                    self.chks[i].setVisible(True)
        for i in range(len(myglobal.fields), len(self.chks)):
            self.chks[i].setVisible(False)
        # self.init_grid()
    def import_std_result(self):
        FileDialog =QtWidgets.QFileDialog(self)
        folder=os.path.join(os.curdir)#os.path.expanduser('~'), "Desktop")
        fil = "xlsx Files (*.xlsx);;All Files (*)"
        FileDirectory = FileDialog.getOpenFileName(
            self, 'select import file', folder, fil)  # 选择目录，返回选中的路径
        fname = FileDirectory[0]
        if fname == "":
            pass
        else:
            try:
                myglobal.db.import_std_result_file(fname)
                # self.edit_standard()
            except:
                traceback.print_exc()
    def edit_standard(self):
        from dlgstandard import Dlgstandard
        myglobal.db.sql_cmd("delete  from curvedata")
        d = Dlgstandard()
        r = d.exec_()
        if r == 1:
            logging.info(r)
            at=0
            for i in range(len(myglobal.fields)):
                if myglobal.fields[i].get("ele") is None:
                    pass
                else:
                    at=i
                    myglobal.db.std_result_to_curvedata(myglobal.fields[i].get("ele"))
            self.model.select()
            self.model.setFilter("ele =  '" + myglobal.fields[at]["ele"]+"'")
        else:
            pass
    def firstChannel(self):
        at=0
        for i in range(len(myglobal.fields)):
            if myglobal.fields[i].get("ele") is None:
                pass
            else:
                at=i
                break
                # myglobal.db.std_result_to_curvedata(myglobal.fields[i].get("ele"))
        self.model.select()
        self.model.setFilter("ele =  '" + myglobal.fields[at]["ele"]+"'")
        myglobal.ele=myglobal.fields[at]["ele"]
    def import_std(self):
        FileDialog =QtWidgets.QFileDialog(self)
        folder=os.path.join(os.curdir)#os.path.expanduser('~'), "Desktop")
        fil = "xlsx Files (*.xlsx);;All Files (*)"
        FileDirectory = FileDialog.getOpenFileName(
            self, 'select import file', folder, fil)  # 选择目录，返回选中的路径
        fname = FileDirectory[0]
        if fname == "":
            pass
        else:
            try:
                myglobal.db.import_std_file(fname)
            except:
                traceback.print_exc() 

    def btnNew_clicked(self):
        '''新建一条数据'''
        data = BaseCalibrationItem()
        data.id = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        data.standard = 0.012
        data.area = 0.011
        data.input = True
        data.include = True
        self.setDatas([data])
        self.baseItems[self.currentChannel].append(data)

    def btnDelete_clicked(self):
        ranges = self.twData.selectedRanges()
        count = len(ranges)
        row = []
        for i in range(0, count):
            for j in range(ranges[i].topRow(), ranges[i].bottomRow() + 1):
                row.append(j)
        row.sort(key=int, reverse=True)  # 因为删除一行后，后面的行号都会变化，所以用sort方法将list进行降序排列
        self.twData.blockSignals(True)
        for i in row:
            self.twData.removeRow(i)
            self.baseItems[self.currentChannel].pop(i)
        self.twData.blockSignals(False)


    def dropEvent(self, a0) -> None:
        """当拖拽操作在目标控件上被释放时，触发"""
        if a0.mimeData().hasText():
            dropstr = a0.mimeData().text()
            # print(dropstr)
            rowindexsstr = dropstr.split("&")
            rowIndexs = []
            for i in rowindexsstr:
                rowIndexs.append(int(i))
            count = len(rowIndexs)
            if count > 0:
                results = device.modelResult.getBaseItems(rowIndexs)
                if len(results) > 0:
                    self.setDatas(results)
                    for i in results:
                        self.baseItems[self.currentChannel].append(i)
        pass

    def dragEnterEvent(self, a0) -> None:
        """拖拽操作时，进入该控件时，触发该事件，"""
        if a0.mimeData().hasText():
            a0.setAccepted(True)
            # print("准备接收drag")
        else:
            a0.setAccepted(False)
            # print("drag不匹配")
        pass
if __name__ == '__main__':
    import sys
    import logging
    import getpath
    initpath=getpath.getpath()
    import logging
    import config_json
    from logging.handlers import RotatingFileHandler
    handlers=[RotatingFileHandler(filename="report.log", maxBytes=10*1024*1024, encoding='utf-8',backupCount=3),# logging.FileHandler(initpath+'/myapp.log'),
        logging.StreamHandler(sys.stdout)]
    logging.basicConfig(level=logging.DEBUG,
                        format = '%(asctime)s - %(name)s - %(levelname)s -%(funcName)s - %(message)s',
                        handlers=handlers)
    logging.info('begin')
    app = QtWidgets.QApplication(sys.argv)
    w = Cali()
    w.setAttribute(Qt.WA_DeleteOnClose)
    w.exec()
    sys.exit(0)
